package tool

import org.slf4j.LoggerFactory
import play.api.data.{Form, FormBinding, FormUtils}
import play.api.http.HttpVerbs
import play.api.libs.Files.TemporaryFile
import play.api.libs.json.JsValue
import play.api.mvc.{AnyContent, MultipartFormData, Request, RequestHeader}
import ujson.play.PlayJson
import upickle.default._
import utils.Utils

import java.io.File
import java.net.URLEncoder
import java.nio.file.Files

/**
 * Created by yz on 3/7/2020
 */
object Tool extends ProjectTool {

  val logger=LoggerFactory.getLogger(this.getClass)

  val projectName = "panda"
  val playPath = new File("../").getAbsolutePath
  val windowsTestDir = new File("C:\\temp")
  val linuxTestDir = new File(playPath, "workspace")
  val testDir = if (windowsTestDir.exists()) windowsTestDir else linuxTestDir
  val dbName = s"${projectName}_database"
  val windowsPath = s"E:\\${dbName}"
  val linuxPath = playPath + s"/${dbName}"
  val path = {
    if (new File(windowsPath).exists()) windowsPath else linuxPath
  }
  val userDir = new File(path, "user")
  val dataDir = new File(path, "data")
  val sampleDir = new File(dataDir, "sample")
  val exampleDir = new File(path, "example")
  val softExampleDir = new File(exampleDir, "soft")
  val dataAvatarDir = new File(dataDir, "avatar")
  val pattern = "yyyy-MM-dd HH:mm:ss"
  val rPath = {
    val rPath = s"C:\\workspaceForIDEA\\${projectName}\\server\\rScripts"
    val linuxRPath = linuxPath + "/rScripts"
    if (new File(rPath).exists()) rPath else linuxRPath
  }

  def createTempDirectory(prefix: String) = {
    Files.createTempDirectory(prefix).toFile
  }

  def deleteDirectory(direcotry: File) = {
    Utils.deleteDirectory(direcotry)
  }

  def fileMoveDir(fieldName: String, dir: File)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    fileMoveDirOp(fieldName, dir).get
  }

  def filesMoveDir(fieldName: String, dir: File)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    request.body.files.filter(_.key == fieldName).toList.flatMap { tempFile =>
      if (tempFile.ref.path.toFile.length() > 0) {
        val destFile = new File(dir, tempFile.filename)
        tempFile.ref.moveTo(destFile, replace = true)
        List(destFile)
      } else List.empty
    }
  }

  def getContentDisposition(url: String) = {
    val encodeUrl = Tool.urlEncode(url)
    s"attachment; filename*=utf-8''${encodeUrl}"
  }

  def urlEncode(url: String) = {
    URLEncoder.encode(url, "UTF-8")
  }

  def fileMoveDirOp(fieldName: String, dir: File)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    val tempFile = request.body.file(fieldName).get
    if (tempFile.ref.path.toFile.length() > 0) {
      val destFile = new File(dir, tempFile.filename)
      tempFile.ref.moveTo(destFile, replace = true)
      Some(destFile)
    } else None
  }

  def jsonParse(jsValue: JsValue) = FormUtils.fromJson(jsValue, Form.FromJsonMaxChars).mapValues(Seq(_))

  def multipartFormParse(body: MultipartFormData[_]) = body.asFormUrlEncoded


  def transformRq(implicit request: Request[AnyContent], formBinding: FormBinding) = {

    val unwrap = request.body match {
      case body: play.api.mvc.AnyContent =>
        body.asFormUrlEncoded.orElse(body.asMultipartFormData).orElse(body.asJson).getOrElse(body)
      case body => body
    }
    unwrap match {
      case body: play.api.libs.json.JsValue =>
        PlayJson.transform(body, reader[ujson.Value])
      case x=>
        val data: Map[String, Seq[String]] = unwrap match {
          case body: Map[_, _] => body.asInstanceOf[Map[String, Seq[String]]]
          case body: MultipartFormData[_] => multipartFormParse(body)
          case Right(body: MultipartFormData[_]) => multipartFormParse(body)
          case _ => Map.empty
        }
        val method: Map[_ <: String, Seq[String]] = request.method.toUpperCase match {
          case HttpVerbs.POST | HttpVerbs.PUT | HttpVerbs.PATCH => Map.empty
          case _ => request.queryString
        }
        val map = (data ++ method).foldLeft(Map.empty[String, String]) {
          case (s, (key, values)) =>
            if (key.endsWith("[]")) {
              val k = key.dropRight(2)
              s ++ values.zipWithIndex.map { case (v, i) => s"$k[$i]" -> v }
            } else {
              s + (key -> values.headOption.getOrElse(""))
            }
        }
        logger.info(s"${map}")
        writeJs(map)
    }
  }

}
